--[[ 怒首领蜂大往生黑版,用的是older版本的文件ddpdojblka,
  因为更主流的ddpdojblk的作弊码有问题!
  
  这次终于更新了坐标算法!是高位的4倍+低位表示0-3共4个像素的下取整,
  即4*低位/256下取整,这次误差终于大大降低!
  
  By setycyas @2025-01-28
]]

-- 这里设定基本参数
GAME = {
  -- 分辨率
  X_RESOLUTION = 224,
  Y_RESOLUTION = 448,
  -- 横坐标纵坐标内存地址,未知时都设定为0
  X_ADDR_HIGH = 0x008103e6,
  X_ADDR_LOW = 0x008103e7,
  Y_ADDR_HIGH = 0x008103e4,
  Y_ADDR_LOW = 0x008103e5,
  -- 如果仅用read_u16读取坐标和计算,就设定为true
  USE_U16 = false,
  -- 坐标最终修正比例
  X_OFFSET = 0.0,
  Y_OFFSET = 0.0,
  --散枪和激光火力等级地址
  SHOT_ADDR = 0x0,
  LASER_ADDR = 0x0,
  -- 自己中心方块的半长半高,单位为MAME的屏幕比例
  BOX_HALF_WIDTH = 0.005,
  BOX_HALF_HEIGHT = 0.005,
  -- 中心方块的边框颜色和中心颜色
  BOX_BORDER_COLOR = 0x88ff0000,
  BOX_COLOR = 0x88ff0000,
  -- 十字方块的边框颜色和中心颜色
  CROSS_BORDER_COLOR = 0x99ff00ff,
  CROSS_COLOR =  0x660000ff,
  -- 十字线颜色,易被自机子弹遮盖,建议设为子弹的反色
  CROSS_LINE_WIDTH = 0.002, --十字线宽度
  CROSS_LINE_COLOR = 0xFFffff00,
  -- 中途需要变更的测试参数,准备了10个,
  -- 预计坐标低位为每字节最大表示4个像素,所以前2参数设定为256/4=64
  TEST_PARAMS = {64.0, 64.0, 208.0, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
  -- mame api用的对象
  mem = manager.machine.devices[':maincpu'].spaces['program'],
  container = manager.machine.screens[":screen"].container,
  ui_container = manager.machine.render.ui_container,
}

-- 刷新设备,成功获取设备返回true,否返回false
function GAME.refreshDevices()
  GAME.mem = manager.machine.devices[':maincpu'].spaces['program']
  GAME.container = manager.machine.screens[":screen"].container
  GAME.ui_container = manager.machine.render.ui_container
  
  if (GAME.mem and GAME.container and GAME.ui_container) then
    return true
  else
    return false
  end
end

-- 坐标变换函数,从得到的坐标变为屏幕显示位置(是个比例),返回0.0-1.0的浮点数,
-- 后期游戏可能很复杂,需要根据游戏的情况手动操作变化
function GAME.getX_u8()
  local xhigh, xlow, result
  xhigh = 0 
  xlow = 0
  if (GAME.X_ADDR_HIGH > 0) then
    xhigh = GAME.mem:read_u8(GAME.X_ADDR_HIGH)
  end
  if (GAME.X_ADDR_LOW > 0) then
    xlow = GAME.mem:read_u8(GAME.X_ADDR_LOW)
  end
  result = 4.0*xhigh
  result = result+math.floor(4.0*xlow/0x100)
  
  result = result+GAME.X_OFFSET
  result= result/GAME.X_RESOLUTION
  return result+GAME.X_OFFSET
end
function GAME.getY_u8()
  local ylow, yhigh, result
  yhigh = 0
  ylow = 0
  if (GAME.Y_ADDR_HIGH > 0) then
    yhigh = GAME.mem:read_u8(GAME.Y_ADDR_HIGH)
  end
  if (GAME.Y_ADDR_LOW > 0) then
    ylow = GAME.mem:read_u8(GAME.Y_ADDR_LOW)
  end
  result = 4.0*yhigh
  result = result+math.floor(4.0*ylow/0x100)
  
  result = result+GAME.Y_OFFSET
  result = result/GAME.Y_RESOLUTION
  return result+GAME.Y_OFFSET
end

function GAME.getX_u16()
  local x
  if (GAME.X_ADDR_HIGH > 0) then
    x = 4.0*GAME.mem:read_u16(GAME.X_ADDR_HIGH)/0x100 --低位是小数部分,要/256
  else
    return -1
  end
  
  --实际像素位置就是x的4倍可能四舍五入!最后计算屏幕比例才除以分辨率!
  result = x/(GAME.X_RESOLUTION) 
  
  return result+GAME.X_OFFSET
end
function GAME.getY_u16()
  local y
  if (GAME.Y_ADDR_HIGH > 0) then
    y = 4.0*GAME.mem:read_u16(GAME.Y_ADDR_HIGH)/0x100 --低位是小数部分,要/256
  else
    return -1
  end
  
  --实际像素位置就是y的4倍可能四舍五入!最后计算屏幕比例才除以分辨率!
  result = y/(GAME.Y_RESOLUTION) 
  
  return result+GAME.Y_OFFSET
end

-- 数据显示,指定位置和颜色,然后是可变的多个显示数据
function GAME.showInfo(position, color, ...)
  local count = select("#", ...)
  
  for i = 1, count do
    local arg = select(i, ...)
    GAME.ui_container:draw_text(position, 1.01-0.05*i, arg, color, 0xFF839496)
  end
  
end

-- 监视数据显示
function GAME.check()
  local xlow, ylow, xhigh, yhigh --内存数据
  local positionY = 0.005
  -- 显示非零地址数值
  if GAME.X_ADDR_HIGH > 0 then
    xhigh = GAME.mem:read_u8(GAME.X_ADDR_HIGH)
    GAME.ui_container:draw_text(0.7, positionY, 
      string.format("xhigh=%d", xhigh), 0xFF000000, 0xFF839496)
    positionY = positionY+0.05
  end
  if GAME.X_ADDR_LOW > 0 then
    xlow = GAME.mem:read_u8(GAME.X_ADDR_LOW)
    GAME.ui_container:draw_text(0.7, positionY, 
      string.format("xlow=%d", xlow), 0xFF000000, 0xFF839496)
    positionY = positionY+0.05
  end
  if GAME.Y_ADDR_HIGH > 0 then
    yhigh = GAME.mem:read_u8(GAME.Y_ADDR_HIGH)
    GAME.ui_container:draw_text(0.7, positionY, 
      string.format("yhigh=%d", yhigh), 0xFF000000, 0xFF839496)
    positionY = positionY+0.05
  end
  if GAME.Y_ADDR_LOW > 0 then
    ylow = GAME.mem:read_u8(GAME.Y_ADDR_LOW)
    GAME.ui_container:draw_text(0.7, positionY, 
      string.format("ylow=%d", ylow), 0xFF000000, 0xFF839496)
    positionY = positionY+0.05
  end
end

-- 显示自机的几个方框,xfloat,yfloat是浮点数坐标
-- 显示中心
function GAME.showCenter(xfloat, yfloat)

  GAME.container:draw_box(
    yfloat-GAME.BOX_HALF_HEIGHT,
    xfloat-GAME.BOX_HALF_WIDTH,
    yfloat+GAME.BOX_HALF_HEIGHT,
    xfloat+GAME.BOX_HALF_WIDTH,
    GAME.BOX_BORDER_COLOR, GAME.BOX_COLOR
  )
  
end
-- 显示十字线
function GAME.showCrossLine(xfloat, yfloat)
  --[[
  -- 横线
  GAME.container:draw_line(
    0.0, xfloat, 1.0, xfloat, GAME.CROSS_LINE_COLOR
  )
  -- 竖线
  GAME.container:draw_line(
    yfloat, 0.0, yfloat, 1.0,GAME.CROSS_LINE_COLOR
  )
  ]]
  -- 横线
  GAME.container:draw_box(
    0.0, xfloat-GAME.CROSS_LINE_WIDTH, 
    1.0, xfloat+GAME.CROSS_LINE_WIDTH, 
    GAME.CROSS_LINE_COLOR, GAME.CROSS_LINE_COLOR
  )
  -- 竖线
  GAME.container:draw_box(
    yfloat-GAME.CROSS_LINE_WIDTH, 0.0,
    yfloat+GAME.CROSS_LINE_WIDTH, 1.0,
    GAME.CROSS_LINE_COLOR, GAME.CROSS_LINE_COLOR
  )
end

--[[ **************************
  主函数,绑定后每一帧执行一次该函数
]]
function GAME.main()
  local xfloat, yfloat -- 最终浮点数坐标

  -- 刷新设备,并判断当前帧能否操作
  if (not GAME.refreshDevices()) then
    return
  end

  -- 获取自己屏幕坐标
  if GAME.USE_U16 then
    xfloat = GAME.getX_u16()
    yfloat = GAME.getY_u16()
  else
    xfloat = GAME.getX_u8()
    yfloat = GAME.getY_u8()
  end
  
  -- 数据监视
  --GAME.check()
  -- 显示角色中心辅助线
  if (xfloat > 0.0) and (yfloat > 0.0) then
    -- 十字线
    GAME.showCrossLine(xfloat, yfloat)
    --十字方框
    --GAME.showCrossBox(xfloat, yfloat)
    -- 中心
    GAME.showCenter(xfloat, yfloat)
  end
  
end

-- 绑定每一帧执行的函数
emu.register_frame_done(GAME.main, "frame")

GAME.refreshDevices()

return GAME
